#include <assert.h>
#include <stdint.h>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <string>
#include "functions.h"
#include "NodeService.h"
#include "mp2_types.h"

using namespace std;
using namespace mp2;
    
string get_ADD_FILE_result_as_string(const char *fname, const int32_t key, const int32_t nodeId)
{
	std::stringstream s;
	s << "fname= " << fname << "\n";
	s << "key= " << key << "\n";
	s << "added to node= " << nodeId << "\n";
	return s.str();
}

string get_DEL_FILE_result_as_string(const char *fname, const int32_t key, const bool deleted, const int32_t nodeId)
{
	std::stringstream s;
	s << "fname= " << fname << "\n";
	s << "key= " << key << "\n";
	if (deleted) {
		// then nodeId is meaningful
		s << "was stored at node= " << nodeId << "\n";
		s << "deleted\n";
	}
	else {
		// assume that this means file was not found
		s << "file not found\n";
	}
	return s.str();
}

string get_GET_FILE_result_as_string(const char *fname, const int32_t key, const bool found, const int32_t nodeId, const char *fdata)
{
	std::stringstream s;
	s << "fname= " << fname << "\n";
	s << "key= " << key << "\n";
	if (found) {
		// then nodeId is meaningful
		s << "stored at node= " << nodeId << "\n";
		s << "fdata= " << fdata << "\n";
	}
	else {
		// assume that this means file was not found
		s << "file not found\n";
	}
	return s.str();
}

string get_GET_TABLE_result_as_string(const vector<NodeInfo>& finger_table, const uint32_t m, const uint32_t myid, const uint32_t idx_of_entry1, const std::map<int32_t, FileMap>& keys_table)
{
	
	string first = get_finger_table_as_string(finger_table, m, myid, idx_of_entry1);
	string second = get_keys_table_as_string(keys_table);
	return first+second;
}

string get_finger_table_as_string(const std::vector<NodeInfo>& table, const uint32_t m, const uint32_t myid, const uint32_t idx_of_entry1)
{
    std::stringstream s;
    assert(table.size() == (idx_of_entry1 + m));
    s << "finger table:\n";
    for (size_t i = 1; (i - 1 + idx_of_entry1) < table.size(); ++i) {
        using std::setw;
        s << "entry: i= " << setw(2) << i << ", interval=["
		<< setw(4) << (myid + (int)pow(2, i-1)) % ((int)pow(2, m))
		<< ",   "
		<< setw(4) << (myid + (int)pow(2, i)) % ((int)pow(2, m))
		<< "),   node= "
		<< setw(4) << table.at(i - 1 + idx_of_entry1).id
		<< "\n";
    }
    return s.str();
}

std::string get_keys_table_as_string(const std::map<int32_t, FileMap>& table)
{
    std::stringstream s;
    std::map<int32_t, FileMap>::const_iterator it = table.begin();
    /* std::map keeps the keys sorted, so our iteration will be in
     * ascending order of the keys
     */
    s << "keys table:\n";
    for (; it != table.end(); ++it) {
        using std::setw;
        /* assuming file names are <= 10 chars long */
        s << "entry: k= " << setw(4) << it->first
		<< ",  fname= " << setw(10) << it->second.name
		<< ",  fdata= " << it->second.data
		<< "\n";
    }
    return s.str();
}
